/***************************Copyright QYKJ   2015-06-18*************************
文	件：	Thread.c
说	明：	线程实现函数
编	译：	Keil uVision4 V4.54.0.0
版	本：	v1.1
编	写：	Unarty
修　改：	2014.06.18 创建 
			2014.08.30 //修改单次延时注册线程，延时零毫秒不能执行问题
			2015.05.02 修改线程查找方式，加快查找速度。修改线程时间变量处理方式，增加线程可移植性 
			2016.08.05 unarty 修改任务结构体，增加任务查找函数，与随机值获取函数
			2016.08.10 unarty 增加任务延时响应注册。
			2016.08.16 Unarty 修改优化任务注册逻辑（减少已注册任务重复查找）;任务换醒立即生效; 随机产生方式（参考C语言）; 增加线程负载统计获取接口
            2021.08.03 Unarty 进一步简化线程任务管理方法，减少本身管理产生的系统资源消耗。
                    1、任务同期心跳计数简化，将任务表中的周期计算置换到，任务执行环节计算。减少中断任务中资源占用，减少系统对其它中断的影响。
                    2、任务注销时不再对任务表单中后面的任务进行移动覆盖等内存操作，将其换成内存有效标记，减少任务注销时资源消耗。
                    3、移除挂起/唤醒的管理接口。（任务的注册/注销占用资源很小，对任务挂起的需求，可通过注销与重新注册的方式实现）
            2021.08.04 Unarty 将任务Tick计数器放置到由外部直接增减，如此即可直接取值相关外设计数器值。减少因线程心跳计数而产生的中断消耗，
            2021.08.25 Unarty  Tick计数器重新归类到管理函数中，保存其变量的整体性
            2021.11.04 Unarty  增加当作任务查找与删除时，直接传参: null。 增加自身任务查找效率
            2022.07.27 Unarty  优化任务注册时，中断禁用与判断，防止中断中任务注册与运行中的任务注册过程中发生重入导致注册失败的可能
            2022.08.20 Unarty  进一步简化线程任务，减少任务注册传参。备注：本次简化会原有注册接口进行改动。
                    1、移除MANY类型注册任务，以前的MANY需求由FOREVER来代替，由任务应用中决定次数与移除。
                        变更理由：MANY任务需求比较少，但需要占用一个任务注册入口的传参位。同时由于任务查找支持NULL 传参功能，大大减小了获取
                                本任务执行次数及注销所消耗资源，综合考虑，将其移除。
                    2、简化任务注册接口，由于MANY任务的移除，任务类型就只有单次任务与永久任务，同时执行次数CNT也不需要再传参默认0即可，所以
                    将注册接口简化，任务类型与频率复用，延时类型注册使用，frep|TH_DELAY, 即：通过最高位判断，为1：延时执行任务，0：周期任务。
                    3、修改任务结构体内容，增加一个任务执行类型（延时/周期）函数指针与参数指针，去除之前的任务类型记录其由任务执行函数替代，同时
                    增加一个参数指针，用于替换函数内部的静态变量，增加内存利用率。该指针初始状态为空，需要用户在使用时自行应用，同时若其申请的为库
                    自带的动态内容分部空间部分，在任务注销时会主动释放。
                    4、优化任务周期匹配计算方法，减少周期匹配计算消耗。
                    5、任务名称由之前的，单次延时与永久任务的叫法更改为：延时任务与周期任务
                    6、周期任务在注册后会在稍后立即执行一次。
            2022.08.20 Unarty 再次优化任务执行，将之前的查表执行移值到运行中直接执行，通过复用频率来记录任务类型，减少一个函数指针变量，同时也减少任务执行
                    过程中的入栈等操作。
            2022.08.22 Unarty 将任务表有效标记方法，由任务自行标记修改为位标记方法，即通过一个无符号长整形变量的每一个bit位，对应标记任务表中有效任务，
                    bit = 1, 有效， 0：无效， 
                    优点：相对之前减少了一个有效任务结束位置指针，线程变量中减少了一个标记变量。进一步减少代码量与执行效率（判断尽量多与零做比较）。
                    缺点: 变更后就默认最多支持32个任务同时在线，之前定义为31可修改，理论上32个任务可以满足绝大数要求，因为很多任务执行结束后即退出。
            2022.08.24 Unarty 应用过程中发现将参数指针放置到线程内部管理不太实用，故将其传参由注册接口处传入，注销时不参与其释放的过程。参数折生命周期由
                    应用者管理。 同时为减小线程占用空间，将次数据与周期都改为无符号短整形数。
                    备注：注册延时线程时，线程参数处请传Null,因为延时任务传参将不被使用
            2022.09.10 Unarty 为适应某些应用场景下不需要这么多线程，用户可以依据需求配置，故增加线程数据宏定义代码。
            2022.09.25 Unarty 增加数据类型定义，以适应8位单片机之类的应用，减少线程管理对系统的消耗
            2022.10.15 Unarty 修改Bug，flag变量变更前后增加中断停止代码，防止中断重入导致注册任务失效。
            2022.10.22 Unarty 利用Cortex -M 内核位操作方法，实现对标记位修改时无需考虑被中断打断的风险
*******************************************************************************/
#include "Thread.h"
#include "Public.h"



typedef struct {
    TICK_TYPE   	tick;   
    FLAG_TYPE      flag;
    Thread_t    *run; //当前运行任务
    Thread_t    tab[TH_COUNT];
}ThreadManage_t;


static ThreadManage_t _thread = {0};
#if USER_BIT == 1 
static u32_t *flagBitAddr;

static inline void _threadClear(Thread_t *th) {

    *(flagBitAddr + (th - _thread.tab)) = 0;
}
#endif

/*******************************************************************************
功能说明:    Thread_init 线程资源初始化
    参数:   none
  返回值:   none
*******************************************************************************/
void Thread_init(void) {
    _thread.flag = 0;
#if USER_BIT == 1 
    flagBitAddr = (u32_t*)(BIT_START_ADDR | (((u32_t)&_thread.flag - RAM_START_ADDR)<<5));
#endif
}

/*******************************************************************************
功能说明:    Thread_login 线程注册 
    参数:   conf:   线程类型，conf&0x7FFFFFFF为任务周期，最高位1： 延时任务，0：周期任务 
            fun:   线程入口函数地址
            para:  线程参数地址
  返回值:   注册任务参数值，null: 注册失败。
*******************************************************************************/
Thread_t * Thread_login(u32_t conf, void_fun_void fun, void *para) {
    VAL_TYPE i;
    Thread_t  *p, *pTh;
    /*找空缺位置, 如下执行条件中，i 是否等于0 判断越界， flag > i 判断是否到表格的最后一个有效任务*/
    for (i = 1, pTh = null, p = _thread.tab; TH_RANGE && ((_thread.flag > i) || (pTh == null)); i <<= 1, p++) {
        if (0 != (_thread.flag&i)) {
            
            if (p->exeFun == fun) {
                if (pTh != null) { //释放最靠前位置
                #if USER_BIT == 1
                    _threadClear(pTh);
                #else 
                    IRQ_disable();
                    _thread.flag ^= (0x01U << (pTh - _thread.tab));
                    IRQ_enadble();
                #endif
                }
                pTh = p;
                break;
            }
            
        } else if (pTh == null) { //最靠前的空缺位置优先
            IRQ_disable();
            if (0 == (_thread.flag&i)) { //避免中断重入，导致一个线程空间被重复使用
                _thread.flag |= i;
                p->exeFun = fun;
                pTh = p;
            }
            IRQ_enadble();
        } 
    }
    
    if (pTh != null ) {
        if (conf&TH_DELAY) { //延时任务
            pTh->tick = _thread.tick + (conf&(~TH_DELAY));
            pTh->para = (void*)fun;
        } else {
            pTh->cnt = 0;
            pTh->freq = (u16_t)conf;
            pTh->tick = _thread.tick;
            pTh->para = para;
        }
    }

    return pTh;
}

/*******************************************************************************
功能说明:    Thread_logout 线程注销
    参数:   fun:   函数入口地址 
  返回值:   无
*******************************************************************************/
void Thread_logout(void_fun_void fun) {

    if (fun == null) {
    #if USER_BIT == 1
        _threadClear(_thread.run);
    #else
        IRQ_disable();
        _thread.flag &= ~(0x01U << (_thread.run - _thread.tab));
        IRQ_enadble();
    #endif
    } else {
        VAL_TYPE i;
        Thread_t *pTh;

        for (i = 1, pTh =_thread.tab; TH_CONF _thread.flag >= i; i <<=1, pTh++) {
            if ((0 != (_thread.flag & i)) && (pTh->exeFun == fun)) {
            #if USER_BIT == 1
                _threadClear(pTh);
            #else
                IRQ_disable();
                _thread.flag ^= i;
                IRQ_enadble();
                break;
            #endif
            }
        }
    }
}
/*******************************************************************************
功能说明:    Thread_tick 线程心跳， 此函数的调用频率即为任务管理器的心跳周期。
    参数:   无
  返回值:   无
*******************************************************************************/
void Thread_tick(void) {

    _thread.tick++;
}

/*******************************************************************************
功能说明:   线程查找
    参数:   fun:   函数入口地址 
  返回值:   null：未找到。非NNULL：线程的所有参数值
*******************************************************************************/
Thread_t *Thread_find(void_fun_void fun) {

    if (fun == null) {
        return _thread.run;
    } else {
        VAL_TYPE i;
        Thread_t *pTh;

        for (i = 1, pTh =_thread.tab; TH_CONF _thread.flag >= i; i <<=1, pTh++) {
            if ((0 != (_thread.flag & i)) && (pTh->exeFun == fun)) {
                return pTh;
            }
        }
    
        return null;
    }
}

/*******************************************************************************
功能说明:  线程处理， 函数需在任务
    参数:  无
  返回值:  当前任务表中有效任务标记状态
*******************************************************************************/
VAL_TYPE Thread_run(void) {
    VAL_TYPE i;

    for (i = 1, _thread.run =_thread.tab; TH_CONF _thread.flag >= i; i <<= 1, _thread.run++) {
        if (0 != (i & _thread.flag)) {

            if (_thread.run->tick > _thread.tick) {
                if ((int)(_thread.run->tick - _thread.tick) > 0) {
                    continue;
                }
            } else if ((int)(_thread.tick - _thread.run->tick) < 0)  {
                continue;
            } 

            if (_thread.run->para == (void*)_thread.run->exeFun) { //延时任务
                void_fun_void fun = _thread.run->exeFun;
            #if USER_BIT == 1
                _threadClear(_thread.run);
            #else
                IRQ_disable();
                _thread.flag ^= i; // 注销任务
                IRQ_enadble();
            #endif
                fun();
            } else { //周期任务
                _thread.run->tick = _thread.tick + _thread.run->freq;
                _thread.run->cnt++;
                _thread.run->exeFun();
            }
        }
    } 

    return  _thread.flag;
}
/*******************************************************************************
功能说明:  随机数
    参数:  无
  返回值:  依据任务特性而产生的随机数
*******************************************************************************/
VAL_TYPE Thread_rand(void){
    VAL_TYPE random;

    random = _thread.tick;
    random <<= 11;
    random += _thread.tick<<6;
    random += _thread.tick;
      
    return random;
}
/*******************************************************************************
功能说明:  线程心跳总数
    参数:  无
  返回值:  系统执行到现在的累计值
*******************************************************************************/
VAL_TYPE Thread_tickCount(void){
    return _thread.tick;
}

/*******************************Copyright QYKJ*********************************/
